home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-02
/
seabool2.zip
/
SEABOOL.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1990-02-16
|
34KB
|
917 lines
unit seabool; {COPYRIGHT 1990 by Peter Neuendorffer}
{compiler options: BOOLEAN SHORT CIRCUIT SHOULD BE ON}
{STACK CHECKING MUST BE ON}
{IF USING EDITSTRING OR LOWERCASE,
RELAXED STRING CHECKING MUST BE SET}
{CHANGES SEABOOL VERSION 1.1:
bool_validation_sit codes sorted better
2=invalid- too complicated or wrong syntax for condition
4=logically never true
-------------------------
range test corrected in lowercase}
interface
const
punct = [')','(',' '];
type
letter_type = 'a'..#123;
hash_function_type=function :boolean; {type parity for
procedural parameter}
hash_procedure_type=procedure(var internal_string :string;var valid:boolean);
{for any_bool unit code}
var
and_op,or_op :boolean;
bool_recursion_depth_0 : byte; {for fence routine}
max_bool_recursion_depth: byte; {when recursion is}
{deemed too deep}
bool_validation_sit : byte; {REFLECTS STATUS OF USER_BOOLEAN STRING}
{1=ok,2=bad,
4=always_false,100=not initialized
User must call bool_init for each new
boolean string at least once before
actual first call to bool() for that
boolean string!}
{ARRAY OF CURRENT BOOLEAN VARIABLES}
search_object_hash_table_0 : array [letter_type] of
string;
length_object_hash_table_0 : letter_type;
{this hash table contains a list of all valid
string primary search objects within a
given boolean search string. This table
is set and used during bool_init function
to return the bool_validation_sit analysis
code of the boolean target string provided
by the end-user.}
current_object_hash_table_index_0 : 'a'..'z'; {where in history table we
are when translating to
symbolics}
{SMART LINK VARIABLES:}
test_source_string:string;
bool_crit_true : array['a'..#123] of boolean;{note however,
this array only valid after
call to bool_init, and for
possible indexes 'b'..'y'}
critical_test_letter: letter_type;
{------------------------------------------------------}
{TWO INTERFACE CALLS FOR BOOLEAN ENGINE::::}
procedure bool_init(user_boolean_string : string);
function any_bool(user_defined_procedure : hash_procedure_type) :boolean;
{------------------------------------------------------}
procedure Editstring ( var newstring : string);
function Lowercase(convert_string : string) :string;
{converts a string to lowercase}
implementation
{RELATED SERVICES editstring and lowercase}
procedure Editstring ( var newstring : string);
type
byte_array_string_typcast = array[1..257] of byte;
var
letter : integer;
allspaces, finished
: boolean;
newstring_byte_pointer :^byte_array_string_typcast;
begin
if newstring='' then
exit;
{check for all spaces}
allspaces:=true;
letter:=1;
while ((allspaces) and (letter<=length(newstring))) do
if newstring[letter]<>' ' then
allspaces:=false
else
Inc(letter);
if allspaces=true then
newstring:=''
{check for leading, trailing blanks}
else
begin
letter:=1;
while newstring[letter]=#32 do
Inc(letter);
newstring:=copy(newstring,letter,length(newstring)-letter+1);
letter:=length(newstring);
while newstring[letter]=#32 do
Dec(letter);
newstring:=copy(newstring,1,letter);
{edit string for all lower case}
{edit string for all lower case}
newstring_byte_pointer:=@newstring;{effects
typscast of string
to array of bytes}
for letter:=2 to newstring_byte_pointer^[1]+1 do
if (newstring_byte_pointer^[letter] <91) and
(newstring_byte_pointer^[letter] >64)
then
Inc(newstring_byte_pointer^[letter],32);
end{meat}
end{procedure editstring};
function Lowercase(convert_string : string) :string;
{converts a string to lowercase}
var
letter :integer;
lengthofconvertstring : integer;
begin
Lowercase:=convert_string;
if convert_string='' then exit;
lengthofconvertstring:=byte(convert_string[0]);
for letter:=1 to lengthofconvertstring do
if (convert_string[letter] <#91) and
(convert_string[letter] >#64) then
Lowercase[letter]:=chr(byte(convert_string[letter])+$20);
end;
{************end related service routines*************}
{INTERNAL GLOBALS}
type
kind_type=(UNKNOWN,NOTT,ORR,ANND,PRIMARY,BAD); {type of boolean binary
infix operator,primary
indicates a unary
object}
var
{FOR ANYBOOL UNIT CODE}
op_str : array [1..3] of string[3]; {constants for divide procedure}
op_kind : array[1..3] of kind_type;{constants for divide procedure}
op_leng : array[1..3] of byte;
work_string_interface_pass : string; {used ONLY to pass a string in and
out of obtain_hash_table procedure}
hash_user_target_string : string;
{actually used internally. would look something
like '1 and 2 or (3 and not(1))' it is a boolean
with the numbers refering to the index object in
the hash table.}
hash_table_formatted_0 : boolean;
all_value_bit_mask : byte;
{used to cycle through all possible boolean
values of given user_target_string
object set.}
{**************************************}
{ANYOOL UNIT CODE**********************}
procedure remove_paren_and_edit(var boolean_work_string :
string);
{THIS PRIMITIVE REMOVES OUTSIDE MATCHING SAME_LEVEL PARENTHESES
IF FOUND AND PARSES LEADING AND TRAILING BLANKS FROM
A STRING}
var
c1 : byte;
level : integer;
match : boolean;
leng : byte;
BEGIN
{empty string}if boolean_work_string='' then
begin
bool_validation_sit:=2;
exit
end;
{SCAN FOR VALID number left,right parentheses}
level:=0;
if ((Pos('(',boolean_work_string)=0) and
(Pos(')',boolean_work_string)=0)) then
level:=0
else
for c1:=1 to length(boolean_work_string) DO
begin
if boolean_work_string[c1]='(' then
Inc(level)
else if boolean_work_string[c1]=')' then
begin
Dec(level);
if level<0 then level:=10000 {force bad}
end;
end;
if (level<>0) then
begin
boolean_work_string:='';
bool_validation_sit:=2;
EXIT
end;
{MEAT!}
match:=true;
Repeat
Editstring(boolean_work_string); {remove blanks tolower}
leng:=length(boolean_work_string);
c1:=1;
level:=0;
if boolean_work_string='()' then {empty parens}
begin
boolean_work_string:='';
bool_validation_sit:=2
end
else if leng=1 then
match:=false
else
if leng=0 then {blanks or null
in middle}
begin
match:=false;
bool_validation_sit:=2;
end
else
begin
While ( (match) and (c1<=leng) and (bool_validation_sit<>2))
DO
BEGIN
if ((c1=1) and (boolean_work_string[1]<>'(' ))
then match:=false;
if boolean_work_string[c1]='(' then Inc(level)
else if boolean_work_string[c1]=')' then Dec(level);
if ((match) and (level=1) and (c1=leng-1) and
(boolean_work_string[c1+1]<>')' )) then
match:=false
else
if ((level=0) and (c1>1) and (c1<leng)) then
match:=false; {matched
parens
before
end}
INC(c1);
END;
{CHANGE STRING}
if level<>0 then
begin
match:=false;
bool_validation_sit:=2;
end;
if ((match) and (leng>=3))
then
boolean_work_string:=copy(boolean_work_string,2,
ord(boolean_work_string[0])-2);
END{ELSE};
Until ((not match) or (bool_validation_sit=2));
Editstring(boolean_work_string);
END;{procedure remove_paren_and_edit}
procedure divide_string(var user_boolean_string:string;var left_half :string;
var right_half :string;var expression_kind :kind_type);
VAR
c1,letter :byte;
op_count : byte;
leng : byte; {op_l_leng is length of operator string name,
leng is length of user_boolean_string}
level: integer;
op_l_leng : byte;
{kind_type=(UNKNOWN,NOTT,ORR,ANND,PRIMARY,BAD); type of boolean binary
infix operator,primary
indicates a unary
object}
BEGIN
expression_kind:=UNKNOWN;
op_count:=1;
leng:=length(user_boolean_string);
{MAIN DETERMINE TYPE LOOP************************************}
WHILE ((expression_kind=UNKNOWN) and (op_count<=3) ) DO
BEGIN
op_l_leng:=op_leng[op_count];
letter:=1;
level:=0;
if leng>=op_l_leng then
While ((expression_kind=UNKNOWN)and
(letter<= leng)) do
begin
if user_boolean_string[letter]=')' then
Dec(level)
else if user_boolean_string[letter]='(' then
Inc(level)
else if ((level=0) and
(copy(user_boolean_string,letter,op_l_leng)=
op_str[op_count])) then
{---------------------------------------------------}
if leng=op_l_leng then
expression_kind:=BAD {only operator}
else
if ((op_count<3) and (letter=1) {and, or,}
and (user_boolean_string[letter+
op_l_leng] in
punct ))
then
expression_kind:=BAD {operator starts}
else
if ((letter=leng-op_l_leng+1) and
(user_boolean_string[letter-1] in
punct )) then
expression_kind:=BAD {operator ends}
else
if ((letter>1) and (op_count<3) and
(letter<=leng-op_l_leng) and
(user_boolean_string[letter-1] in
punct ) and
(user_boolean_string[letter+op_l_leng] in
punct ))
then
begin
expression_kind:=op_kind[op_count];
left_half:=copy(user_boolean_string,1,
letter-1);
right_half:=copy(user_boolean_string,letter+
op_l_leng,400);
end {valid or/ and}
else
if ((letter=1) and (op_count=3)
and (user_boolean_string[4] in
punct)) then
begin
expression_kind:=NOTT; {valid not}
left_half:=copy(user_boolean_string,4,
400);
right_half:='';
end;
{-----------------------------------------}
Inc(letter);
end{letter scan};
Inc(op_count);
END{WHILE LOOP};
{END MAIN DETERMINE TYPE LOOP************************************}
if expression_kind=UNKNOWN then
expression_kind:=PRIMARY;
if expression_kind=PRIMARY then
for c1:=1 to length(user_boolean_string) do
if ((user_boolean_string[c1]='(' ) or
(user_boolean_string[c1]=')' )
or
(copy(user_boolean_string,c1,5)=' not ')) then
begin
expression_kind:=BAD;
left_half:='';
right_half:='';
end;
if expression_kind=BAD then
bool_validation_sit:=2{bad code};
if expression_kind=PRIMARY then
begin
left_half:=user_boolean_string;
right_half:='';
end;
END;{procedure divide_string}
{OBJECT FOR BOOL_INIT}
{$F+}
function obtain_hash_object :boolean;{object function passed by init_bool
to first_bool}
{$F-}
var
value_found: boolean;
counter : letter_type;
found_0 :boolean;
BEGIN
found_0:=false;
counter:='b';
if length_object_hash_table_0='a' then {FIRST VARIABLE NAME}
begin
length_object_hash_table_0:='b';
search_object_hash_table_0['b']:=
work_string_interface_pass;
work_string_interface_pass:='b';
found_0:=true;
end;
if found_0=false then
while (counter<= length_object_hash_table_0)
do
begin
if (work_string_interface_pass
= search_object_hash_table_0[counter])
then
begin
found_0:=true;
work_string_interface_pass :=counter;
end;
counter:=succ(counter);
end;
if not found_0 then
if counter<='z' then {NEW VARIABLE}
begin
search_object_hash_table_0[counter]:=
work_string_interface_pass;
work_string_interface_pass:=counter;
length_object_hash_table_0:=
succ(length_object_hash_table_0);
end
else {TOO MANY VARIABLES}
begin
bool_validation_sit:=2;
work_string_interface_pass:='';
length_object_hash_table_0 :='a';{disable further init}
hash_user_target_string :='';{disable further init}
end;
END;
{OBJECT FOR BOOL_INIT}
{$F+}
procedure for_all_boolean_values_object(var target_string :string;
var valid:boolean);
{2nd object function passed by init_bool
to first_bool}
BEGIN
valid:= Pos(target_string,
test_source_string)>0;
END;
{$F-}
{MAIN INTIALIZATION ENGINE}
function first_bool(var work_string :string;work_function
: hash_function_type) :boolean;
const
spc=' ';
not_spc='not ';
var
left_hlf,right_hlf : string;
bool_expression_kind_0 :kind_type;
left_result,right_result,dummy_result : boolean;
BEGIN
Inc(bool_recursion_depth_0);
{NOTE:bool_recursion_depth_0 is a counter
used to report
a 2-bad in
bool_validation_sit
if too many recursions involved}
if bool_recursion_depth_0 >max_bool_recursion_depth
then
bool_validation_sit:=2;
if bool_validation_sit=2 then
begin
first_bool:=false;
work_string:='';
length_object_hash_table_0 :='a';{disable further init}
hash_user_target_string :='';{disable further init}
end;
first_bool:=false;
bool_expression_kind_0 :=UNKNOWN;
bool_validation_sit:=0;
remove_paren_and_edit(work_string);
if bool_validation_sit<>2{bad} then
BEGIN
divide_string(work_string,left_hlf,right_hlf,
bool_expression_kind_0 );
{NOTE POSSIBLE RETURNS FROM DIVIDE ARE :UNKNOWN,NOTT,ORR,ANND,PRIMARY,BAD}
first_bool:=false;{fallthrough default}
{****} if bool_expression_kind_0=
{****} BAD then
bool_validation_sit:=2{bad}
else if bool_expression_kind_0=
{****} ORR then {------WE WILL DIVIDE AND RECURSE!!!----}
{****} BEGIN
and_op:=false;
{****} left_result:=first_bool(left_hlf,work_function);
if bool_validation_sit<>2 then
right_result:=first_bool(right_hlf,
{****} work_function);
{****} if bool_validation_sit=2 then
else
first_bool:=left_result or right_result;
{****} END{divide select}
else if bool_expression_kind_0=
{****} ANND then{------WE WILL DIVIDE AND RECURSE!!!----}
{****} BEGIN
{****} left_result:=first_bool(left_hlf,work_function);
if bool_validation_sit<>2 then
right_result:=first_bool(right_hlf,
{****} work_function);
{****} if bool_validation_sit=2 then
else
first_bool:=left_result and right_result;
{****} END{divide select}
{****}
{****}
{****} else if bool_expression_kind_0=
NOTT then
begin
and_op:=false;
or_op:=false;
left_result:=not(first_bool(left_hlf,work_function));
if bool_validation_sit=2 then
else
first_bool:=left_result;
end
else if bool_expression_kind_0=
{****} PRIMARY then
begin
work_string:=left_hlf;
work_string_interface_pass:=work_string;
{actually only needed for obtain_hash_object
first pass, but harmless otherwise}
dummy_result:=work_function;
if (not hash_table_formatted_0)
then
work_string:=work_string_interface_pass;
if length(work_string)>1 then
bool_validation_sit:=2;
end;
{****} {UNKNOWN : begin}
{****} {Writeln('boolean program divide error');}
{****} {halt}
{****}
{****} {end;}
{****}
END{DIVIDE PART};
if bool_validation_sit=2 then {no good code, then return
false}
begin
first_bool:=false;
work_string:='';
length_object_hash_table_0 :='a';{disable further init}
hash_user_target_string :='';{disable further init}
end
ELSE {GOOD SO FAR-----------FORMAT RETURN SYMBOLIC BINARY INFIX}
if bool_expression_kind_0 in
{****} [NOTT,ORR,ANND] then
{------WE WILL COMBINE STRING BINARY!!!----}
begin
if bool_expression_kind_0=ANND then
if (length(left_hlf)+length(right_hlf)
+5<=255) then
work_string:='('+left_hlf+'and'+right_hlf+
')'
else
bool_validation_sit:=2
else
if bool_expression_kind_0=ORR then
if (length(left_hlf)+length(right_hlf)+
4<=255) then
work_string:='(' +left_hlf+'or'+right_hlf+
')'
else
bool_validation_sit:=2
else
if bool_expression_kind_0=NOTT then
if length(left_hlf)+6<=255 then
work_string:='('+ not_spc+left_hlf+')'
else
bool_validation_sit:=2;
end
else if bool_expression_kind_0 =
PRIMARY then work_string:=spc+work_string+spc;
{case return string symbolic binary formatting}
END{main initialization parser engine function};
function test_bool(var work_string :string;work_procedure
: hash_procedure_type) :boolean;
{used for testing critical variables}
var
left_hlf,right_hlf : string;
bool_expression_kind_0 :kind_type;
left_result,right_result : boolean;
{FOR PASSING IN TO END_USER_PROCEDURE}
user_pass_in_string :string;
user_primary_search_result :boolean;
BEGIN
test_bool:=false;
if bool_validation_sit=2 then exit;
Inc(bool_recursion_depth_0);
{NOTE:bool_recursion_depth_0 is a counter
used to report
a 2-bad in
bool_validation_sit
if too many recursions involved}
bool_expression_kind_0 :=UNKNOWN;
remove_paren_and_edit(work_string);
divide_string(work_string,left_hlf,right_hlf,
bool_expression_kind_0 );
{NOTE POSSIBLE RETURNS FROM DIVIDE ARE :UNKNOWN,NOTT,ORR,ANND,PRIMARY,BAD}
{****} if bool_expression_kind_0 =
{****} PRIMARY then
begin
work_procedure(left_hlf,
user_primary_search_result);
test_bool:=user_primary_search_result
end
{****} else if bool_expression_kind_0=
{****} ORR then{------WE WILL DIVIDE AND RECURSE!!!----}
{****} test_bool:=test_bool(left_hlf,work_procedure)
or
{****} test_bool(right_hlf,
work_procedure)
{****}
else if bool_expression_kind_0=
{****} ANND then
{****}
{------WE WILL DIVIDE AND RECURSE!!!----}
test_bool:=test_bool(left_hlf,work_procedure)
and
{****} test_bool(right_hlf,
work_procedure)
{****}
{****}
{****}
else if bool_expression_kind_0=
{****} NOTT then
test_bool:=not(test_bool(left_hlf,work_procedure));
{****}
{****} {UNKNOWN : begin}
{****} {Writeln('divide error');}
{****} { halt}
{****}
{****} {end;}
{****}
END{main active WE_HAVE_A_GO parser engine function};
procedure bool_init(user_boolean_string : string);
var
dummy : boolean;
all_bool_test_string:string;
generation_string:string;{used for critical true testing}
variable_add:letter_type;
true_once: boolean;
procedure determine_crit_true(
generation_string:string;var variable_add:letter_type);
{this SUB procedure tests all possible letter combinations of
our boolean for a possible truth value with test_letter
not present. therefore we can determine of a given variable
is not critical to the truth value of a boolean. The
bool_crit_true array has been initialized to all true before
first call to this}
var
pass_variable_add:letter_type;
begin
pass_variable_add:=Succ(variable_add);
if pass_variable_add > length_object_hash_table_0
then
begin
test_source_string:=generation_string;
if test_bool(all_bool_test_string,for_all_boolean_values_object)
=true then
begin
true_once:=true; {our expression is true at least once}
if Pos(critical_test_letter,generation_string)=0 then
bool_crit_true[critical_test_letter]:=false;
{a given variable is not critical}
end
end
else
begin
determine_crit_true(generation_string,
pass_variable_add);
generation_string:=generation_string+pass_variable_add;
determine_crit_true(generation_string,
pass_variable_add);
end;
end;
BEGIN {MAINLINE PROCEDURE BOOL_INIT}
and_op:=true;
or_op:=true;
true_once:=false;
bool_validation_sit:=1;{default good until proven otherwise}
if user_boolean_string='' then
bool_validation_sit:=2;
{INITIALIZE OPERATORS FOR DIVIDE PROCEDURE}
op_str[1] :='or';
op_kind[1]:=ORR;
op_leng[1]:=2;
op_str[2] :='and';
op_kind[2]:=ANND;
op_leng[2]:=3;
op_str[3] :='not';
op_kind[3]:=NOTT;
op_leng[3]:=3;
bool_validation_sit:=1;{default good until proven otherwise}
length_object_hash_table_0 :='a';{will be table of symbolic objects}
bool_recursion_depth_0 :=0;{counter used to report
a 2-bad in
bool_validation_sit
if too many recursions involved}
hash_table_formatted_0:=false;
dummy:=first_bool(user_boolean_string,obtain_hash_object);
if bool_validation_sit<>2 then
hash_user_target_string:=user_boolean_string;
{NOTE USER_BOOLEAN UNIT COPY HAS NOW BEEN TRANSFORMED if sit code
<>2 to a symbolic string 'a or b and c' for ex.}
bool_recursion_depth_0 :=0;
hash_table_formatted_0:=true; {important bug flag}
all_bool_test_string:=hash_user_target_string;
{initialize bool crit list}
if bool_validation_sit<>2 then
for critical_test_letter:='b' to length_object_hash_table_0 do
bool_crit_true[critical_test_letter]:=true;
if bool_validation_sit=2 {bad} then
begin
length_object_hash_table_0 :='a';{disable further init}
hash_user_target_string :='';{disable further init}
end
ELSE
begin
{determine bool_crit_true array of variables}
for critical_test_letter:='b' to length_object_hash_table_0 do
if length_object_hash_table_0< 'g' then
begin
generation_string:='a';
variable_add:='a';
determine_crit_true(generation_string,
variable_add);
end
else
begin
bool_crit_true[critical_test_letter]:=false;
true_once:=true;
end;
if (bool_validation_sit <>2) and (not true_once)
then bool_validation_sit:=4;
end;
END{procedure init_bool};
function bool(var work_string :string;work_procedure
: hash_procedure_type) :boolean;
var
left_hlf,right_hlf : string;
bool_expression_kind_0 :kind_type;
left_result,right_result : boolean;
{FOR PASSING IN TO END_USER_PROCEDURE}
user_pass_in_string :string;
user_primary_search_result :boolean;
BEGIN
bool:=false;
if bool_validation_sit=2 then exit;
Inc(bool_recursion_depth_0);
{NOTE:bool_recursion_depth_0 is a counter
used to report
a 2-bad in
bool_validation_sit
if too many recursions involved}
bool_expression_kind_0 :=UNKNOWN;
remove_paren_and_edit(work_string);
divide_string(work_string,left_hlf,right_hlf,
bool_expression_kind_0 );
{NOTE POSSIBLE RETURNS FROM DIVIDE ARE :UNKNOWN,NOTT,ORR,ANND,PRIMARY,BAD}
{****} if bool_expression_kind_0 =
{****} PRIMARY then
begin
user_pass_in_string:=
search_object_hash_table_0[left_hlf[1]];
work_procedure(user_pass_in_string,
user_primary_search_result);
bool:=user_primary_search_result
end
{****} else if bool_expression_kind_0=
{****} ORR then{------WE WILL DIVIDE AND RECURSE!!!----}
{****} bool:=bool(left_hlf,work_procedure)
or
{****} bool(right_hlf,
work_procedure)
{****}
else if bool_expression_kind_0=
{****} ANND then
{****}
{------WE WILL DIVIDE AND RECURSE!!!----}
bool:=bool(left_hlf,work_procedure)
and
{****} bool(right_hlf,
work_procedure)
{****}
{****}
{****}
else if bool_expression_kind_0=
{****} NOTT then
bool:=not(bool(left_hlf,work_procedure));
{****}
{****} {UNKNOWN : begin}
{****} {Writeln('divide error');}
{****} { halt}
{****}
{****} {end;}
{****}
END{main active WE_HAVE_A_GO parser engine function};
function any_bool(user_defined_procedure : hash_procedure_type) :boolean;
begin
any_bool:=false;
if bool_validation_sit=2 then
exit;
any_bool:=bool
(hash_user_target_string,user_defined_procedure);
end;{function shell any_bool}
{INITIALIZATION}
begin
max_bool_recursion_depth:=24;
bool_validation_sit:=100;
end.{unit seabool}